////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "WNPlatform/inc/WNSurfaceXWindows.h"
#include "WNConcurrency/inc/WNThread.h"

using namespace WNPlatform;



WNNativeGraphicsHandle WNSurfaceXWindows::GetNativeGraphicsHandle() {
    return(mWindow);
}

WNSurface::WNSurfaceError WNSurfaceXWindows::Resize(WN_UINT32, WN_UINT32) {
    return(eWNOK);
}

WNSurface::WNSurfaceError WNSurfaceXWindows::Move(WN_UINT32, WN_UINT32) {
    return(eWNOK);
}

WN_BOOL WNSurfaceXWindows::IsFullscreen() {
    return(WN_FALSE);
}

WNSurface::WNSurfaceError WNSurfaceXWindows::SetFullscreen(WN_BOOL) {
    return(eWNOK);
}

WN_UINT32 WNSurfaceXWindows::GetWidth() const {
    return(mWidth);
}

WN_UINT32 WNSurfaceXWindows::GetHeight() const {
    return(mHeight);
}

WN_UINT32 WNSurfaceXWindows::GetX() const {
    return(mX);
}

WN_UINT32 WNSurfaceXWindows::GetY() const {
    return(mY);
}

WNSurfaceXWindows::WNSurfaceXWindows(WNPlatform::WNSurfaceManagerXWindows& _surfaceManager):
    mManager(_surfaceManager),
    mDisplay(WN_NULL),
    mWindow(0),
    mWindowThread(WN_NULL),
    mExiting(WN_FALSE){
}

WNSurfaceXWindows::~WNSurfaceXWindows() {
    mExiting = WN_TRUE;
    if(mWindow && mWindowThread) {
        XDestroyWindow(mDisplay, mWindow); 
        mWindowThread->Join();
    }
    mWindow = 0;
    mWindowThread = WN_NULL;
}

WN_BOOL WNSurfaceXWindows::Initialize(WN_UINT32 _x, WN_UINT32 _y, WN_UINT32 _width, WN_UINT32 _height, Display* _display, XVisualInfo* _visualInfo) {
    WN_RELEASE_ASSERT(_display != WN_NULL);
    mDisplay = _display;
    XSetWindowAttributes swa;
    swa.colormap = XCreateColormap( mDisplay, RootWindow( mDisplay, _visualInfo->screen ), _visualInfo->visual, AllocNone );
    swa.background_pixmap = None ;
    swa.border_pixel      = 0;
    swa.event_mask        = StructureNotifyMask;


    mWindow = XCreateWindow( mDisplay, RootWindow(mDisplay, _visualInfo->screen), _x, _y, _width, _height, 0, _visualInfo->depth, InputOutput, _visualInfo->visual, CWBorderPixel|CWColormap|CWEventMask, &swa );
    if(!mWindow) {
        return(WN_FALSE);
    }
    XSelectInput(_display, mWindow, StructureNotifyMask);
    XMapWindow(_display, mWindow);
    mDeleteMessage = XInternAtom(mDisplay, "WM_DELETE_WINDOW", True);
    XSetWMProtocols(mDisplay, mWindow, &mDeleteMessage, 1);
    mWindowThread = WN_NEW(WNConcurrency::WNThread(&SurfaceThread, this));
    return(WN_TRUE);
}

WN_VOID WNSurfaceXWindows::SurfaceThread(WNSurfaceXWindows* _surface) {
    while(1) {
        XEvent e;
        while(XCheckWindowEvent(_surface->mDisplay, _surface->mWindow, StructureNotifyMask, &e)) {
            switch(e.type) {
            case ConfigureNotify:
                {
                    XConfigureEvent* xce = &e.xconfigure;
                    _surface->mWidth = xce->width;
                    _surface->mHeight = xce->height;
                    _surface->mX = xce->x;
                    _surface->mY = xce->y;
                    _surface->FireCallback(eSETResize);
                }
                break;
            case ClientMessage:
                {
                    XClientMessageEvent* xce = &e.xclient;
                    printf("GOTCLIENTMESSAGE\n");
                    if(xce->format == 32) {
                        if(xce->data.l[0] == _surface->mDeleteMessage) {
                            return;
                        }
                    }
                }
                break;
            }
        }
        WNConcurrency::WNThreadSleep(1);
        if(_surface->mExiting) {
            return;
        }
    }
}